#ifndef RS485_DRIVER
#define RS485_DRIVER

#ifndef RS485_ID
#define RS485_ID  0xFE                 // The device's RS485 address or ID
#endif

#ifndef RS485_RX_PIN
#define RS485_RX_PIN       PIN_B1   // Data receive pin
#endif

#ifndef RS485_TX_PIN
#define RS485_TX_PIN       PIN_B2   // Data transmit pin
#endif

#ifndef RS485_ENABLE_PIN
#define RS485_ENABLE_PIN   PIN_A1   // Controls DE pin.  RX low, TX high.
#endif


#use rs232(baud=9600, xmit=RS485_TX_PIN, rcv=RS485_RX_PIN, bits=8,stream=RS485)

#define RS485_wait_time 20             // Wait time in milliseconds

#define bittime 105 // bittime(us) = (1000/BAUD)*1000

#bit TRMT = 0x98.1 //flag verdadeira quando o buffer do usart tiver vazio
#bit CREN = 0x18.4 //continuos receive enable bit, pra resetar o usart
#bit FERR = 0x18.2 //frame error
#bit OERR = 0x18.1 //overrun error

//#bit    rs485_collision = rs232_errors.6

#ifndef RS485_BUFFER_SIZE
#define RS485_BUFFER_SIZE  40
#endif

unsigned int8 rs485_rbuffersz;
unsigned char rs485_rbuffer[RS485_BUFFER_SIZE];
unsigned int8 rs485_sbuffersz;
unsigned char rs485_sbuffer[RS485_BUFFER_SIZE];
unsigned int rs485_hasMsg;
unsigned char checksum;
unsigned char pktn;

int1 timer_enabled;

void rs485_send_raw(int8 len, int8* data);

void rs485_wait_for_bus()
{
   int16 i;
   int1 nivel=0;
   
   for(i=0; i <= (rs485_wait_time*20); ++i)
   {
      if(input(RS485_RX_PIN)==nivel)
      {
         i = 0;
         nivel = !nivel;
      }
      else
         delay_us(50);
   }
}

#int_TIMER1
void  TIMER1_isr(void) 
{
   timer_enabled=false;
}

void rs485_init()
{
   disable_interrupts(INT_TIMER1);
   timer_enabled=false;
   output_low(RS485_ENABLE_PIN);
   rs485_rbuffersz=rs485_sbuffersz=checksum=pktn=0;
   rs485_hasMsg=FALSE;
   while(kbhit(RS485)) fgetc(RS485);
}

void getRDA()
{
   char c;

   if(rs485_rbuffersz>=RS485_BUFFER_SIZE || (rs485_rbuffersz>2 && rs485_rbuffersz>(rs485_rbuffer[2]+6))) rs485_rbuffersz=0; // pra nao estourar o buffer

   c = fgetc(RS485);
   if(rs485_rbuffersz==0 && c!='$') return;
   //if(rs485_rbuffersz>4 && c=='$' && rs485_rbuffersz<(rs485_rbuffer[2]+5)) rs485_rbuffersz=0;
   if(rs485_rbuffersz==0) checksum=0;
   checksum ^= c;
   rs485_rbuffer[rs485_rbuffersz++] = c;
   
   if(rs485_rbuffersz>4 && (rs485_rbuffer[2]+6)<=rs485_rbuffersz)
   {
     if(checksum==0)
     {
         if(rs485_rbuffer[4]==RS485_ID && rs485_rbuffer[5]!= 0x01) // confirma o recebimento do pacote
         {
            delay_ms(10);
            c = '$'^rs485_rbuffer[1]^0x01^RS485_ID^rs485_rbuffer[3]^0x01;
            rs485_wait_for_bus();
            output_high(RS485_ENABLE_PIN);
            fputc('$',RS485);   
            fputc(rs485_rbuffer[1],RS485);   
            fputc(0x01,RS485);   
            fputc(RS485_ID,RS485);  
            fputc(rs485_rbuffer[3],RS485);  
            fputc(0x01,RS485);
            fputc(c,RS485);
            while(TRMT==0);
            delay_us(bittime);
            output_low(RS485_ENABLE_PIN);
         }
         rs485_hasMsg=true;
     }
     else 
         rs485_rbuffersz=0;
   }
}

int8 rs485_get_message(int8* data)
{
   int8 i;

   if(OERR || FERR) // verifica se tem um erro na uart e reseta
   {
      CREN=0;
      delay_cycles( 1 );
      CREN=1;
   }

   while(kbhit(RS485)&&!rs485_hasMsg) getRDA();
   if(!rs485_hasMsg) return 0;
   
   for(i=0; i<rs485_rbuffersz; ++i,++data)
   {
      *data = rs485_rbuffer[i];
   }

   rs485_hasMsg=FALSE;
   i=rs485_rbuffersz;
   rs485_rbuffersz=0;
   
   return i;
}

int1 rs485_send_message(int8 to, int8 len, int8* data)
{
   int8 i,try;
   int1 ret=false;
   char cs=0;
   if(pktn==255) pktn=0; else pktn++;
   
   rs485_sbuffer[0] = '$';   
   rs485_sbuffer[1] = pktn;   
   rs485_sbuffer[2] = len;   
   rs485_sbuffer[3] = RS485_ID;   
   rs485_sbuffer[4] = to;   
   rs485_sbuffersz=5;
   
   cs = '$'^pktn^len^RS485_ID^to;

   for(i=0; i<len; ++i)
   {
      cs ^= *data;
      rs485_sbuffer[i+5] = *data;
      ++data;
      rs485_sbuffersz++;
   }
   rs485_sbuffer[rs485_sbuffersz++] = cs;
   
   for(try=1;try<4;++try)
   {
      if(OERR || FERR) // verifica se tem um erro na uart e reseta
      {
         CREN=0;
         delay_cycles( 1 );
         CREN=1;
      }
   
      rs485_wait_for_bus();
      
      output_high(RS485_ENABLE_PIN);
      
      for(i=0; i<rs485_sbuffersz; ++i)
      {
        fputc(rs485_sbuffer[i], RS485);
      }
      
      while(TRMT==0); // enquanto o tx buffer nao estiver vazio
      delay_us(bittime); // aguarda o stop bit ser enviado
      output_low(RS485_ENABLE_PIN);

      enable_interrupts(INT_TIMER1);
      timer_enabled=true;
         
      while(timer_enabled)
      {
         while(kbhit(RS485)&&!rs485_hasMsg) getRDA();
         if(rs485_hasMsg)
         {
            rs485_hasMsg=false;
            rs485_rbuffersz=0;
            if(rs485_sbuffer[1] == rs485_rbuffer[1] && rs485_sbuffer[3] == rs485_rbuffer[4] && rs485_sbuffer[4] == rs485_rbuffer[3])
            {
               disable_interrupts(INT_TIMER1);
               timer_enabled=false;
               ret=true;
               goto sair;
            }
         }
      }
      disable_interrupts(INT_TIMER1);
      delay_ms(10*RS485_ID);
   }
   sair:
   return ret;
}

void rs485_send_raw(int8 len, int8* data)
{
   int8 i;
   
   output_high(RS485_ENABLE_PIN);
   for(i=0; i<len; ++i)
   {
      fputc(*data, RS485);
      ++data;
   }
   
   while(TRMT==0); // enquanto o tx buffer nao estiver vazio
   delay_us(bittime);
   output_low(RS485_ENABLE_PIN);

}
